package javagamecontroller.activities;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import javagamecontroller.connection.BluetoothMessenger;
import com.javagamecontroller.R;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.app.Activity;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;


/**
 * This class is the first activity of the android game controller app. It will
 * list all the bluetooth
 * devices your phone is connected to, prompt you to turn bluetooth on if it is
 * not on, allow you to make
 * your phone discoverable to pair with your computer. Finally, once successful
 * bluetooth connection is established
 * the app moves to the controller selection screen.
 * 
 * @author Ben Schwab,
 *         Built with Android Open Source Project, BlueCove Open Source Project
 * 
 */
public class ConnectScreen extends Activity implements OnClickListener {

    // Constants for background updates to UI
    /**
     * String id for connection updates.
     */
    public static final String ACTION = "action";
    /**
     * The connection was a success.
     */
    public static final int CONNECT_SUCCESS = 1;
    /**
     * The connection was a failure.
     */
    public static final int CONNECT_FAILURE = 2;

    private static final int MAC_LENGTH = 17;

    private static final String NONE_PAIRED = "None Paired.";

    // UUID bluetooth ports
    private static final UUID MY_UUID_ONE = UUID.fromString("04c6093b-0000-1000-8000-00805f9b34fb");
    private static final UUID MY_UUID_TWO = UUID.fromString("14c6093b-0000-1000-8000-00805f9b34fb");
    private static final UUID MY_UUID_THREE = UUID
            .fromString("24c6093b-0000-1000-8000-00805f9b34fb");
    private static final UUID MY_UUID_FOUR = UUID
            .fromString("34c6093b-0000-1000-8000-00805f9b34fb");

    private HashSet<String> myNewDiscovers;

    // View fields
    private ListView myDeviceList;
    private Button myDiscoverButton;
    private RadioGroup myRadioGroup;
    private Button myHelpButton;

    // progress bar fields
    private TextView myProgressText;
    private ProgressBar myProgressBar;

    // Adapters for bluetooth connections
    private ArrayAdapter<String> myPairedDevicesAdapter;
    private ArrayAdapter<String> myNewDevicesAdapter;

    // bluetooth connection fields
    private BluetoothAdapter myBluetoothAdapter;
    private BluetoothMessenger myMessenger;

    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_connect_screen);
        initializeLayoutViews();
        hideProgressBar();
        initializeBluetooth();
        myMessenger.setVibrator((Vibrator) getSystemService(Context.VIBRATOR_SERVICE));
    }

    /**
     * Find views and initialize adapters.
     */
    private void initializeLayoutViews () {
        myPairedDevicesAdapter = new ArrayAdapter<String>(this, R.layout.list_text);
        myNewDevicesAdapter = new ArrayAdapter<String>(this, R.layout.list_text);
        myNewDiscovers = new HashSet<String>();
        myDeviceList = (ListView) findViewById(R.id.device_list);
        myProgressBar = (ProgressBar) findViewById(R.id.discover_progress_bar);
        myProgressText = (TextView) findViewById(R.id.progress_text);
        myDeviceList.setAdapter(myPairedDevicesAdapter);
        myDeviceList.setOnItemClickListener(myListClickListener);
        myDiscoverButton = (Button) findViewById(R.id.make_discoverable);
        myDiscoverButton.setOnClickListener(this);
        myHelpButton = (Button) findViewById(R.id.help_button);
        myHelpButton.setOnClickListener(this);
        myRadioGroup = (RadioGroup) findViewById(R.id.radioGroup1);
    }

    /**
     * Get all devices that are paired with the android devices. Create objects
     * to find and create new connections.
     */
    private void initializeBluetooth () {
        myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        myMessenger = BluetoothMessenger.getInstance();
        Set<BluetoothDevice> pairedDevices = myBluetoothAdapter.getBondedDevices();
        if (pairedDevices.size() > 0) {
            for (BluetoothDevice device : pairedDevices) {
                myPairedDevicesAdapter.add(device.getName() + "\n" + device.getAddress());
            }
        }
        else {
            myPairedDevicesAdapter.add(NONE_PAIRED);
        }
        IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(myReceiver, foundFilter);
        IntentFilter discoverFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        this.registerReceiver(myReceiver, discoverFilter);
    }

    @Override
    public boolean onCreateOptionsMenu (Menu menu) {
        getMenuInflater().inflate(R.menu.activity_connect_screen, menu);
        return true;
    }

    /**
     * When the activity is destroyed stop the bluetooth adapter from being
     * discoverable and unregister
     * the bluetooth receiver.
     */
    @Override
    public void onDestroy () {
        super.onDestroy();
        if (myBluetoothAdapter != null) {
            myBluetoothAdapter.cancelDiscovery();
        }
        this.unregisterReceiver(myReceiver);
    }

    /**
     * Decide what to do on the click event from the given view.
     */
    public void onClick (View arg0) {
        switch (arg0.getId()) {
            case R.id.make_discoverable:
                doDiscovery();
                break;
            case R.id.help_button:
                showHelp();
                break;
            default:
                break;
        }
    }

    /**
     * Start device discover with the BluetoothAdapter
     */
    private void doDiscovery () {
        if (myBluetoothAdapter.isDiscovering()) {
            myBluetoothAdapter.cancelDiscovery();
        }

        myBluetoothAdapter.startDiscovery();
        showProgressBar();

    }

    /**
     * Show the progress bar with the same string as the last time method was
     * called.
     */
    private void showProgressBar () {
        myProgressBar.setVisibility(View.VISIBLE);
        myProgressBar.setIndeterminate(true);
        myProgressText.setVisibility(View.VISIBLE);
    }

    /**
     * 
     * @param waitMessage Message to display beneath progress bar
     */
    private void showProgressBar (String waitMessage) {
        myProgressBar.setVisibility(View.VISIBLE);
        myProgressBar.setIndeterminate(true);
        myProgressText.setText(waitMessage);
        myProgressText.setVisibility(View.VISIBLE);
    }

    /**
     * Hide the progress bard and explanation text.
     */
    private void hideProgressBar () {
        myProgressBar.setVisibility(View.INVISIBLE);
        myProgressText.setVisibility(View.INVISIBLE);
    }

    /**
     * Start a background thread to connect to a bluetooth server.
     * 
     * @param address the MAC address of the device you which to connect to
     */
    private void connectToDevice (String address) {
        BluetoothDevice device = myBluetoothAdapter.getRemoteDevice(address);
        if (device != null) {
            showProgressBar("Connecting to server...");
            myMessenger.connect(device, this, handler);

        }
    }

    /**
     * 
     * @param controllerNumber
     * @return return the UUID being used for this device
     */
    public UUID getActiveUUID () {

        switch (myRadioGroup.getCheckedRadioButtonId()) {
            case R.id.radio0:
                return MY_UUID_ONE;
            case R.id.radio1:
                return MY_UUID_TWO;
            case R.id.radio2:
                return MY_UUID_THREE;
            case R.id.radio3:
                return MY_UUID_FOUR;
            default:
                break;

        }
        return MY_UUID_ONE;

    }

    /**
     * Cancel server discovery.
     */
    public void cancelDiscovery () {
        myBluetoothAdapter.cancelDiscovery();
    }

    private void connectFailed () {
        Toast.makeText(ConnectScreen.this,
                       "The connection to the server failed. Make sure bluetooth is turned on and you are connecting to the right controller number",
                       Toast.LENGTH_LONG).show();
        hideProgressBar();
    }

    private void connectSucces () {
        hideProgressBar();
        Toast.makeText(ConnectScreen.this, "The connection to the server succeeded!",
                       Toast.LENGTH_LONG).show();
        Intent i = new Intent(this, SelectController.class);
        startActivity(i);

    }

    private void showHelp () {
        Dialog d = new Dialog(this);
        d.setContentView(R.layout.help_dialogue);
        d.setTitle("Help Menu");
        TextView helpText = (TextView) d.findViewById(R.id.help_dialogue);
        helpText.setText(R.string.help_text);
        d.show();

    }

    /**
     * A handler to receive connection updates from the connector thread.
     */
    final Handler handler = new Handler() {
        @Override
        public void handleMessage (Message msg) {
            switch (msg.getData().getInt(ACTION)) {
                case CONNECT_SUCCESS:
                    connectSucces();
                    break;
                case CONNECT_FAILURE:
                    connectFailed();
                    break;
            }
            super.handleMessage(msg);
        }
    };

    private final OnItemClickListener myListClickListener = new OnItemClickListener() {

        public void onItemClick (AdapterView<?> adapter, View view, int pos, long id) {
            cancelDiscovery();
            String info = ((TextView) view).getText().toString();
            if (info.equals(NONE_PAIRED)) { return; }
            String address = info.substring(info.length() - MAC_LENGTH);

            connectToDevice(address);

        }
    };
    /**
     * Adds new devices found after discovery to the connected device list.
     */
    private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive (Context context, Intent intent) {
            String action = intent.getAction();
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                    myPairedDevicesAdapter.add(device.getName() + "\n" + device.getAddress());
                    if (myNewDiscovers.add(device.getName() + "\n" + device.getAddress())) {
                        myNewDevicesAdapter.add(device.getName() + "\n" + device.getAddress());
                    }
                }
            }
            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
                setProgressBarIndeterminateVisibility(false);
                if (myNewDevicesAdapter.getCount() == 0) {
                    Toast.makeText(ConnectScreen.this, "No devices found", Toast.LENGTH_LONG)
                            .show();
                }
                hideProgressBar();

            }
            myDeviceList.refreshDrawableState();
            myNewDevicesAdapter.clear();
        }
    };

}
